#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import base64
import getopt
import hashlib
import json
import os
import random
import re
import sys
import time
import xml.etree.ElementTree as ET
from math import radians, cos, sin, asin, sqrt
from urllib import parse

import requests

"""
本程序会假设 kml 的路径里程 > 有效里程
本程序会自动保证路径所经历的时间 > 有效时间
"""
# ==============================================================
# ----------------------配置 开始---------------------------
# 两个坐标的时间间隔,单位: s
# 请根据记录 Kml 的软件中的设置调整
interval = 5
# 要求的有效里程，单位：米
TravelLength = 3000
# 要求的有效时间，单位：秒
StayTime = 3600
# ----------------------------------------------------------
# 终端软件登录用户名、密码、手机串号、轨迹时间、Kml文件路径
app_login_name = ""
app_login_password = ""
app_login_imei = ""
app_version = "4.4.0"
app_routeDate = ""
app_routeKMLFile = ""
# 网站用户名和密码
web_username = ""
web_password = ""

# 坐标点开始时间,默认以当前系统时间开始,如果用户输入,则以输入为准
# 这里减去要求时间 是为了防止发送未来时间，系数1.1与下方有效时间系数一致
routeTime = time.time() - StayTime * 1.1
# ---------------------------------------------------------
# ------------------- 从参数取得数据 开始-------------------
argv = sys.argv[1:]
try:
    opts, args = getopt.getopt(argv, "hu:p:i:t:f:a:s:",
                               ["help", "user=", "pwd=", "imei=", "time=", "file=", "admin=", "admin pwd="])
except getopt.GetoptError:
    sys.exit(2)
for opt, arg in opts:
    if opt in ("-h", "--help"):
        print('test.py -u <username> -p <password> -i <IMEI> -t [route\'s time]-f <route\'s kml file> -a <admin> -s '
              '<admin pwd>')
        sys.exit()
    elif opt in ("-u", "--user"):
        app_login_name = arg
    elif opt in ("-p", "--pwd"):
        app_login_password = arg
    elif opt in ("-i", "--imei"):
        app_login_imei = arg
    elif opt in ("-t", "--time"):
        # 坐标点时间,默认以当前系统时间开始,如果用户输入,则以输入为准,时间格式 "2018-2-26 13:28:01"
        app_routeDate = arg
    elif opt in ("-f", "--file"):
        app_routeKMLFile = arg
    elif opt in ("-a", "--admin"):
        web_username = arg
    elif opt in ("-s", "admin pwd"):
        web_password = arg
# 如果指定轨迹开始时间,则使用
if len(app_routeDate) > 0:
    routeTime = time.mktime(time.strptime(app_routeDate, '%Y-%m-%d %H:%M:%S'))


# ------------------- 从参数取得数据 结束-------------------
# ==============================================================
# ==============================================================
# 自定义方法开始
# ==============================================================
def log_app_person_login(_login_name, _login_password, _app_version):
    """
        登录 APP ，并返回信息

        参数
        ----------
        login_name : string
            app 登录名
        login_password : string
            app 登录密码
        _app_version: string
            app 版本

        返回值
        -------
        string
            app 服务器返回的字符串
    """
    # 登录的URL
    _loginURL = "http://gps.senruansoft.com/CWCF.svc"
    # 登录 Post 的 body 部分
    _body = """<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><Operate 
    xmlns="http://www.senruansoft.com/" id="o0" c:root="1"><action i:type="d:string">PersonLogin</action><param 
    i:type="d:string">[{{"loginName":"{0}","loginPass":"{1}","appVersion":"{2}"}}]</param></Operate>
    </v:Body></v:Envelope>""".format(_login_name, _login_password, _app_version)
    # post 的 header
    _headers = {
        'user-agent': "ksoap2-android/2.6.0+",
        'soapaction': "http://www.senruansoft.com/IWCF/Operate",
        'content-type': "text/xml;charset=utf-8",
        'accept-encoding': "gzip",
        'connection': "Keep-Alive"
    }
    # post 登录信息
    _response = requests.request("POST", _loginURL, data=_body, headers=_headers)
    # post 返回的内容
    return _response.text


def log_app_person_update(_person_id, _imei, _app_version, _phoneInfo):
    """
        登录 APP ，并返回信息

        参数
        ----------
        _personID : string
            个人ID
        _imei : string
            手机imei
        _app_version: string
            app 版本
        _phoneInfo:string
            手机型号

        返回值
        -------
        string
            app 服务器返回的字符串
    """
    # 登录的URL
    _loginURL = "http://gps.senruansoft.com/CWCF.svc"
    # 登录 Post 的 body 部分
    _body = """<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><Operate 
    xmlns="http://www.senruansoft.com/" id="o0" c:root="1"><action i:type="d:string">PersonUpdate</action><param 
    i:type="d:string">[{{"personID":"{0}","imei":"{1}","appVersion":"{2}","phoneInfo":"{3}"}}]</param></Operate></v:Body></v:Envelope>""" \
        .format(_person_id, _imei, _app_version, _phoneInfo)
    # post 的 header
    _headers = {
        'user-agent': "ksoap2-android/2.6.0+",
        'soapaction': "http://www.senruansoft.com/IWCF/Operate",
        'content-type': "text/xml;charset=utf-8",
        'accept-encoding': "gzip",
        'connection': "Keep-Alive"
    }
    # post 登录信息
    _response = requests.request("POST", _loginURL, data=_body, headers=_headers)
    # post 返回的内容
    return _response.text


def get_distance(lon1, lat1, lon2, lat2):
    """
    计算两个 GPS 坐标点之间的距离 (经纬度以十进制度数表示)

    参数
    ----------
    lon1 : float
        坐标1的经度
    lat1 : float
        坐标1的纬度
    lon2 : float
        坐标2的经度
    lat2 : float
        坐标2的纬度

    返回值
    -------
    float
        两点间的距离，单位为 m
    """
    # 将十进制度数转化为弧度
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    # haversine公式
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
    c = 2 * asin(sqrt(a))
    r = 6371  # 地球平均半径，单位为公里
    return c * r * 1000


def login_gps_manage_web(user_name, user_pass):
    """
        登录管理网站，并获取返回的信息

        参数
        ----------
        user_name : string
            网站用户名
        user_pass : string
            网站密码

        返回值
        -------
        string
            网站返回的字符串
    """
    # 密码经过 md5 加密后发送
    m_user_pass = hashlib.md5(user_pass.encode("utf8")).hexdigest()
    # 转换成大写
    m_user_pass = m_user_pass.upper()
    # 将 XXXXXX 字符串转换为 XX-XX-XX格式
    m_user_pass = '-'.join(re.findall('..', m_user_pass))

    url = "http://gps.senruansoft.com/Handle/Config.ashx?action=UserLogin"
    m_headers = {
        'Host': "gps.senruansoft.com",
        'Connection': "keep-alive",
        'Content-Length': "71",
        'Accept': "*/*",
        'Origin': "http://gps.senruansoft.com",
        'X-Requested-With': "XMLHttpRequest",
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/70.0.3538.110 Safari/537.36",
        'DNT': "1",
        'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
        'Referer': "http://gps.senruansoft.com/",
        'Accept-Encoding': "gzip, deflate",
        'Accept-Language': "zh-CN,zh;q=0.9"
    }
    m_body = "userName=" + user_name + "&userPass=" + m_user_pass
    login_web_response = requests.request("POST", url, data=m_body, headers=m_headers)
    return login_web_response.text


def build_persons_travel_record(m_user_id, m_unit_id, m_real_name, m_limit, mlat, mlng, m_map_level, m_unit_name):
    """
        生成个人行程数据。发送数据后，如果不生成，在统计中是无法看到的。下面的参数，直接从登录信息取得的，不需了解详情。

        参数
        ----------
        m_user_id : string
            网站登录名 ID
        m_unit_id : string
            所在单位 ID
        m_real_name : string
            所在单位名称
        mlat : string
            登录后地图纬度
        mlng : string
            登录后地图经度
        m_map_level : string
            地图缩放级别
        m_report_colum : string
            显示列表
        m_unit_name : string
            也是单位名称
        返回值
        -------
        string
            网站返回的字符串
    """
    # 生成个人行程数据的 URL
    url = "http://gps.senruansoft.com/Handle/Real.ashx?action=BuildPersonsTravelRecord"
    m_headers = {
        'Host': "gps.senruansoft.com",
        'Origin': "http://gps.senruansoft.com",
        'X-Requested-With': "XMLHttpRequest",
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/70.0.3538.110 Safari/537.36",
        'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
        'Referer': "http://gps.senruansoft.com/UI/Main.html",
        'Cookie': "UserID=" + m_user_id,
        'Cookie': "UnitID=" + m_unit_id,
        'Cookie': "RealName=" + m_real_name,
        'Cookie': "Limit=" + m_limit,
        'Cookie': "Lat=" + mlat,
        'Cookie': "Lng=" + mlng,
        'Cookie': "MapLevel=" + m_map_level,
        'Cookie': "UnitName=" + m_unit_name
    }
    m_body = "personID=" + personID + "&dataTime=" + time.strftime("%Y-%m-%d", time.localtime(routeTime))
    upload_response = requests.request("POST", url, data=m_body, headers=m_headers)
    return upload_response.text


def post_gps(url, post_body):
    """
        将 GPS 数据发送到后台。

        参数
        ----------
        url:string
            发送目标服务器的 URL
        post_body : string
            post 数据的 body 部分

        返回值
        -------
        string
            网站返回的字符串，目前来说 UploadLocationResult 为1,即为正确
    """
    upload_headers = {
        'content-type': "text/xml",
        'user-agent': "ksoap2-android/2.6.0+",
        'soapaction': "http://www.senruansoft.com/IWCF/Operate",
        'accept-encoding': "gzip",
        'connection': "Keep-Alive",
        'charset': "utf-8"
    }
    upload_response = requests.request("POST", url, data=post_body, headers=upload_headers)
    # print(upload_response.text)
    return upload_response.text


def push2webchat(text, desp):
    """
        通过 server 酱将消息发送到微信。

        参数
        ----------
        text : string
            消息标题，最长为256，必填。
        desp : string
            消息内容，最长64Kb，可空，支持MarkDown。

    """
    api = "https://sc.ftqq.com/SCT5745T8TDjPyw6Y9UqrZK619jPlPLD.send"
    data = {
        "text": text,
        "desp": desp
    }
    requests.request("POST", api, data=data)
    return


def push2bark(tile, text, device_key):
    """
        通过 server 酱将消息发送到微信。

        参数
        ----------
        tile : string
            消息标题，必填。
        text : string
            消息内容，必填。
        device_key : string
            推送设备的ID

    """
    # 发送内容
    data_dict = {"body": text, "device_key": device_key, "title": tile}

    try:
        response = requests.post(
            url="https://api.day.app/push",
            headers={
                "Content-Type": "application/json; charset=utf-8",
            },
            data=json.dumps(data_dict)
        )
        # print('Response HTTP Status Code: {status_code}'.format(status_code=response.status_code))
        # print('Response HTTP Response Body: {content}'.format(content=response.content))
    except requests.exceptions.RequestException:
        print('HTTP Request failed')
    return


def get_person_pic(username):
    """
        随机从个人文件夹下读取一张图片

        参数
        ----------
        username : 用户名

        返回值
        -------
        string
            个人文件夹下的文件名

    """
    file_names = []
    for parent, dir_names, filenames in os.walk(username):  # 三个参数：分别返回1.父目录 2.所有文件夹名字（不含路径） 3.所有文件名字
        file_names = filenames
    _x = random.randint(0, len(file_names) - 1)
    return file_names[_x]


def base64pic(path):
    """
        将图片 base64 编码为网站需要的格式

        参数
        ----------
        path : 图片文件的完整路径名,包含后缀

        返回值
        -------
        string
            base64 编码后的字符串

    """
    with open(path, 'rb') as f:
        base64_data = base64.b64encode(f.read())
    # base64 编码后没有前缀 data:image/jpeg;base64,
    # bytes 转为 string
    return base64_data.decode("utf-8")


def upload_pic(url, _file_name, _file_bytes, _app_version):
    """
        将采集照片上传到网站

        参数
        ----------
        url : 服务器的地址

        _file_Name : 图片的文件名称

        _fileBytes : 图片的 base64 编码

        _appVersion : 软件版本

        返回值
        -------
        string
            是否成功

    """

    upload_headers = {
        'content-type': "text/xml",
        'user-agent': "ksoap2-android/2.6.0+",
        'soapaction': "http://www.senruansoft.com/IWCF/Operate",
        'accept-encoding': "gzip",
        'connection': "Keep-Alive",
        'charset': "utf-8"
    }

    post_body = """<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:d="http://www.w3.org/2001/XMLSchema" 
    xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
    <v:Header/><v:Body><Operate xmlns="http://www.senruansoft.com/" id="o0" c:root="1">
    <action i:type="d:string">UploadFile</action><param i:type="d:string">
    [{{"fileName":"{0}","fileBytes":"{1}","appVersion":"{2}"}}]</param></Operate></v:Body></v:Envelope> """ \
        .format(_file_name, _file_bytes, _app_version)
    upload_response = requests.request("POST", url, data=post_body, headers=upload_headers)
    return upload_response


def upload_pic_loc(url, unit_id, person_id, file_name, picture_lat, picture_lng, pic_collect_time, _app_version):
    """
        将采集照片的坐标位置上传到网站

        参数
        ----------
        :param url : 服务器的地址

        :param unit_id : 单位 ID

        :param person_id : 用户 ID

        :param file_name : 图片文件名

        :param picture_lat : 图片 纬度

        :param picture_lng : 图片 经度

        :param pic_collect_time : 图片采集时间

        :param _app_version : 软件版本

        返回值
        -------
        string
            是否成功

    """
    upload_headers = {
        'content-type': "text/xml",
        'user-agent': "ksoap2-android/2.6.0+",
        'soapaction': "http://www.senruansoft.com/IWCF/Operate",
        'accept-encoding': "gzip",
        'connection': "Keep-Alive",
        'charset': "utf-8"
    }

    post_body = """<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" 
    xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header 
    /><v:Body><Operate xmlns="http://www.senruansoft.com/" id="o0" c:root="1"><action 
    i:type="d:string">UploadCollection</action><param i:type="d:string">[{{"unitID":{0},"personID":{1},
    "attachment":"{2}","remarks":"","lat":{3},"lng":{4},"devTime":"{5}","appVersion":"{6}"}}]</param></Operate>
    </v:Body></v:Envelope> """ \
        .format(unitID, personID, file_name, picture_lat, picture_lng, pic_collect_time, _app_version)
    upload_response = requests.request("POST", url, data=post_body, headers=upload_headers)
    return upload_response


# ==============================================================
# 自定义方法结束
# ==============================================================


# 登录 app ，并接收返回的字符串
# 个人登录
log_info = log_app_person_login(app_login_name, app_login_password, app_version)
log_info = log_info[log_info.index(">[") + 2:log_info.index("]<")]
log_info_dict = eval(log_info)
# post 返回的个人ID
personID = str(log_info_dict["ID"])
# post 返回的 IMEI
responseIMEI = str(log_info_dict["IMEI"])
# 个人信息更新
app_responseTXT = log_app_person_update(personID, responseIMEI, app_version, "samsung-SM-G950F(Android-25)")

# app_responseTXT = log_app_person_login(app_login_name, app_login_password, app_version)
# --------------------根据 post 返回 提取用户信息 开始----------
# 网站返回的字符串转为字典
app_responseTXT = app_responseTXT[app_responseTXT.index(">[") + 2:app_responseTXT.index("]<")]
# app_responseTXT = app_responseTXT.replace("null", "\"test\"")
app_info_dict = eval(app_responseTXT)
# 获取登录网站的相应信息
# 用户ID，post 坐标的时候会用到
personID = str(app_info_dict["ID"])
# unitID，post 坐标的时候会用到
unitID = str(app_info_dict["UnitID"])
# 用户姓名
PersonName = str(app_info_dict["PersonName"])
# post 返回的 IMEI
responseIMEI = str(app_info_dict["IMEI"])
# GPS 区域，post 坐标的时候会用到
ManageArea = str(app_info_dict["ManageArea"])
# 目标服务器的 URL
des_url = str(app_info_dict["Endpoint"])
# 轨迹当前坐标点时间
devTime = ''
# --------------------根据 post 返回 提取用户信息 结束----------
# ==============================================================
# 为了简化程序，要求用户提供有效区域内的坐标点
# 从户外助手导出的轨迹文件得知，其中保存的坐标时间点是不可靠的
# 因此，post 坐标点的时候，日期与时间将由用户指定
# ==============================================================
# *****************从 kml 文件读取坐标点************************
# 列出所有 kml 文件供用户选择
# kml 文件所在的文件夹
# TODO 轨迹路径的指定，需要优化，不应该写死
kml_dir = 'routes'

# -----------------------------------------------------------
tree = ET.parse(os.path.join(kml_dir, app_routeKMLFile))
# 取出 kml 文件中的坐标点
gpsStr = ""
for elem in tree.iter(tag="{http://www.opengis.net/kml/2.2}coordinates"):
    gpsStr = elem.text
    # print(gpsStr)
# 将 gps 坐标点的字符串 分隔为 List
gpsList = gpsStr.split()

# ****************从 kml 文件读取坐标点 结束********************


# -------------------------初始值---------------------------
# 有效里程
dayTrip = 0
# 有效时间
dayTime = 0
# 设备电量,初始值为 90
batteryPower = int(random.uniform(60, 95))
# 是否充电中
charging = False
# 采集照片的时间
pic_time_second = ""
# -------------------------初始值---------------------------
# =======================生成 post 的 body =================
# 上一个坐标点
pre_lng = 0
pre_lat = 0
# 遍历 list  生成 Post 坐标点
# gps_index 为索引,dataStr 为值
gps_index = 0
# 要求的时间 * 1.1 ,是为了保证时间达标
# 时间达标后,自动停止
while dayTime < StayTime * 1.1:
    temp_singleGPS = gpsList[gps_index].split(',')
    # 同时包含经纬度,海拔 才处理
    if len(temp_singleGPS) == 3:
        # 获取上一个坐标点,用于计算距离
        if gps_index == 0 or gps_index == len(gpsList) - 1:
            # 到了最后一个点的时候，当前点就是前一个
            tempStr = gpsList[gps_index].split(',')
        else:
            tempStr = gpsList[gps_index - 1].split(',')
        if len(tempStr) == 3:
            pre_lng = tempStr[0]
            pre_lat = tempStr[1]
        # 当前坐标点
        lng = temp_singleGPS[0]
        lat = temp_singleGPS[1]
        altitude = temp_singleGPS[2]
        # 随机生成 GPS 精度
        accuracy = int(random.uniform(2, 20))
        # 与上一个坐标点的距离
        tempDistance = get_distance(float(lng), float(lat), float(pre_lng), float(pre_lat))
        # 当前速度
        speed = round(3.6 * tempDistance / interval, 2)
        # print(speed)
        # 有效里程
        dayTrip = int(dayTrip + tempDistance)
        # 有效时间
        dayTime = dayTime + interval
        # -----------------------------------------
        # 电量模拟
        # 电量每 200 秒变化 1
        if dayTime % 200 == 0:
            if charging:
                batteryPower = batteryPower + 1
                # 电量 > 98 停止充电
                if batteryPower > 98:
                    charging = False
            else:
                batteryPower = batteryPower - 1
                # 电量 < 10 开始充电
                if batteryPower < 10:
                    charging = True
        # 电量模拟结束
        # -----------------------------------------
        # 生成坐标点时间
        devTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(routeTime))
        # 坐标点时间步进
        routeTime += interval
        # -----------------------------------------
        gis_node_body = """<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" 
        xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header /><v:Body><Operate 
        xmlns="http://www.senruansoft.com/" id="o0" c:root="1"><action 
        i:type="d:string">UploadLocation</action><param i:type="d:string">[{{"unitID":{0},"personID":{1}, 
        "working":false,"lat":{2},"lng":{3},"accuracy":{4},"speed":{5},"altitude":{6},"dayTrip":{7},"dayTime":{8}, 
        "batteryPower":{9},"devTime":"{10}","appVersion":"{11}"}}]</param></Operate></v:Body></v:Envelope>""" \
            .format(unitID, personID, lat, lng, accuracy, speed, altitude, dayTrip, dayTime, batteryPower, devTime,
                    app_version)
        # =============================生成 post 的 body 完成============================
        # TODO 处理发送 GPS 数据后返回的字符串
        post_gps(des_url, gis_node_body)
        # TODO 发送数据，遇到网络连接错误，需要 debug
        # time.sleep(0.1)  # 不知道效果如何。因为在使用中，发现有时候会出现网络连接错误，个人猜测是发送太频繁。
    if gps_index > len(gpsList) / 2:  # 将里程中间点的时间做为采集图片的时间
        pic_time_second = routeTime
    # 索引自增
    if gps_index < len(gpsList) - 1:
        gps_index += 1
    else:  # 如果到达终点，则在终点附近摇摆。（系统中对于静止的点不计算时间）
        # 将终点坐标随机抖动后，放到终点以及前一个坐标点中， 以实现在终点附近摇摆
        temp_singleGPS = gpsList[gps_index].split(',')
        for i in range(gps_index, gps_index - 2, -1):
            # 将终点坐标随机抖动后，放到终点的坐标点中，
            lng = round(float(temp_singleGPS[0]) + random.uniform(0, 1) * 0.0000001, 12)
            lat = round(float(temp_singleGPS[1]) + random.uniform(0, 1) * 0.0000001, 12)
            gpsList[i] = "{0},{1},{2}".format(lng, lat, temp_singleGPS[2])
            # print(gpsList[i])
        gps_index -= 1

# end while
# =========================================================
# 生成个人行程数据
# =========================================================
# 登录 GPS 管理网站，获取返回的信息
web_manage_response_str = login_gps_manage_web(web_username, web_password)
# 网站返回的字符串转为字典
manage_info_dict = eval(
    web_manage_response_str[web_manage_response_str.index("[") + 1:web_manage_response_str.index("]")])
# 获取登录网站的相应信息
w_user_id = str(manage_info_dict["ID"])
w_unit_id = str(manage_info_dict["UnitID"])
w_real_name = parse.quote(manage_info_dict["RealName"])  # url 转码
w_limit = parse.quote(manage_info_dict["Limit"])  # url 转码
w_lat = str(manage_info_dict["Lat"])
w_lng = str(manage_info_dict["Lng"])
w_map_level = str(manage_info_dict["MapLevel"])
# ReportColumn 返回的就是 base64 编码后的字符串，直接使用不需要转换
# w_report_colum = manage_info_dict["ReportColumn"]
w_unit_name = parse.quote(manage_info_dict["UnitName"])  # url 转码

# 生成个人行程数据
result_build_travel = build_persons_travel_record(w_user_id, w_unit_id, w_real_name, w_limit, w_lat, w_lng, w_map_level,
                                                  w_unit_name)
# =========================================================
# 上传照片
# =========================================================
if os.path.exists(app_login_name):
    # 文件名中的 000 从 Android 代码看，应该是毫秒，但是从抓包来看，似乎都是 000，因此这里暂用 000代替。
    filename = """{0}_{1}000{2}.jpg""" \
        .format(personID, time.strftime("%Y%m%d%H%M%S", time.localtime(pic_time_second)), random.randint(0, 900) + 100)
    pic_path = os.path.join(app_login_name, get_person_pic(app_login_name))
    file_bytes = base64pic(pic_path)
    result_upload_pic = upload_pic(des_url, filename, file_bytes, app_version)
    # 删除已经上传的照片
    os.remove(pic_path)
    # 从 GPS 列表中随机取一点做为照片的坐标点
    x = random.randint(0, len(gpsList) - 1)
    temp_singleGPS = gpsList[x].split(',')
    # todo 这里最好做一下容错处理
    pic_lng = temp_singleGPS[0]
    pic_lat = temp_singleGPS[1]
    result_upload_pic_loc \
        = upload_pic_loc(des_url, unitID, personID, filename, pic_lat, pic_lng,
                         time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(pic_time_second)), app_version)
# =========================================================
# 将结果发送到微信
# =========================================================
title_push = "发送行程结果"  # 推送到微信内容的标题
text_push = ""  # 推送到微信内容正文
# 返回 1 ，表示生成行程报表成功 ，-1 表示当前日期没有数据
if 1 == int(result_build_travel):
    result_build_travel = "OK!"
else:
    result_build_travel = "Fail!"
# TODO 行程是否达标，需要另行查询，以上的发送 GPS 数据，无法保证成功
text_push = """用户名：{0}   
日期：{1}   
行程名称：{2}   
行程是否达标:{3}   
生成行程报表：{4}   """ \
    .format(app_login_name, time.strftime("%Y-%m-%d", time.localtime(routeTime)),
            app_routeKMLFile, result_build_travel, result_build_travel)

# push2webchat(title_webchat, text_webchat)
push2bark(title_push, text_push, "GFGzde9SPdZjvf5RtJTCGb")
